package sqlx

import (
	"database/sql"
	"database/sql/driver"
	"gitee.com/gopher2011/sqlx/reflectx"
	"reflect"
	"strings"
	"sync"
)

var (
	NameMapper = strings.ToLower
	origMapper = reflect.ValueOf(NameMapper)
)

// 它不是在init上创建，而是在必要时创建，以便导入者有时间自定义NameMapper。
var (
	mpr *reflectx.Mapper
	mprMu sync.Mutex
)

var (
	scannerInterface = reflect.TypeOf((*sql.Scanner)(nil)).Elem()
	valuerInterface = reflect.TypeOf((*driver.Valuer)(nil)).Elem()
)

// mapper 使用配置的 NameMapper 函数返回有效的映射器。
func mapper() *reflectx.Mapper {
	mprMu.Lock()
	defer mprMu.Unlock()

	if mpr == nil {
		mpr = reflectx.NewMapperFunc("d", NameMapper)
	} else if origMapper != reflect.ValueOf(NameMapper) {
		// if NameMapper has changed, create a new mapper
		mpr = reflectx.NewMapperFunc("d", NameMapper)
		origMapper = reflect.ValueOf(NameMapper)
	}
	return mpr
}

// isScan 接受 reflect.Type 和实际 dest 值，并返回其是否为可扫描。
//   在以下情况下，某些东西是可扫描的:
//   * 它不是一个 struct
//   * 它实现了 sql.Scanner
//   * 它没有导出字段(即: 它的字段首字母小写)
func isScan(t reflect.Type) bool {
	if reflect.PtrTo(t).Implements(scannerInterface) {
		return true
	}
	if t.Kind() != reflect.Struct {
		return true
	}

	// 对于这个特定的对象使用正确的映射器并不重要，我们只关心该结构有多少个导出字段
	return len(mapper().TypeMap(t).Index) == 0
}

// 确定我们的任何扩展程序是否安全
func isUnsafe(i interface{}) bool {
	switch v := i.(type) {
	case Row:
		return v.unsafe
	case *Row:
		return v.unsafe
	case Rows:
		return v.unsafe
	case *Rows:
		return v.unsafe
	case StmtN:
		return v.Stmt.unsafe
	case *StmtN:
		return v.Stmt.unsafe
	case Stmt:
		return v.unsafe
	case *Stmt:
		return v.unsafe
	case qStmt:
		return v.unsafe
	case *qStmt:
		return v.unsafe
	case DB:
		return v.unsafe
	case *DB:
		return v.unsafe
	case Tx:
		return v.unsafe
	case *Tx:
		return v.unsafe
	case sql.Rows, *sql.Rows:
		return false
	default:
		return false
	}
}

func mapperFor(i interface{}) *reflectx.Mapper {
	switch i := i.(type) {
	case DB:
		return i.Mapper
	case *DB:
		return i.Mapper
	case Tx:
		return i.Mapper
	case *Tx:
		return i.Mapper
	default:
		return mapper()
	}
}